# include "jam.h"
# include "filesys.h"
# include "pathsys.h"
# include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ar.h>

#define STRUCT_DIRENT struct dirent
#define SARFMAG 2
#define SARHDR sizeof( struct ar_hdr )

void file_dirscan(
  const char *dir,
  scanback func,
  void *closure ) {
  PATHNAME f;
  DIR *d;
  STRUCT_DIRENT *dirent;
  char filename[ MAXJPATH ];
  memset( ( char * )&f, '\0', sizeof( f ) );
  f.f_dir.ptr = dir;
  f.f_dir.len = strlen( dir );
  dir = *dir ? dir : ".";
  if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' ) {
    ( *func )( closure, dir, 0, ( time_t )0 );
  }
  if( !( d = opendir( dir ) ) ) {
    return;
  }
  if( DEBUG_BINDSCAN ) {
    printf( "scan directory %s\n", dir );
  }
  while( ( dirent = readdir( d ) ) ) {
    f.f_base.ptr = dirent->d_name;
    f.f_base.len = strlen( f.f_base.ptr );
    path_build( &f, filename, 0 );
    ( *func )( closure, filename, 0, ( time_t )0 );
  }
  closedir( d );
}

int file_time(
  const char *filename,
  time_t  *time ) {
  struct stat statbuf;
  if( stat( filename, &statbuf ) < 0 ) {
    return -1;
  }
  *time = statbuf.st_mtime;
  return 0;
}

void file_archscan(
  const char *archive,
  scanback func,
  void *closure ) {
  struct ar_hdr ar_hdr;
  char buf[ MAXJPATH ];
  long offset;
  char    *string_table = 0;
  int fd;
  if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 ) {
    return;
  }
  if( read( fd, buf, SARMAG ) != SARMAG ||
      strncmp( ARMAG, buf, SARMAG ) ) {
    close( fd );
    return;
  }
  offset = SARMAG;
  if( DEBUG_BINDSCAN ) {
    printf( "scan archive %s\n", archive );
  }
  while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
         !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) ) {
    long    lar_date;
    long    lar_size;
    char    lar_name[256];
    char    *dst = lar_name;
    ar_hdr.ar_fmag[0] = 0;
    sscanf( ar_hdr.ar_date, "%ld", &lar_date );
    sscanf( ar_hdr.ar_size, "%ld", &lar_size );
    if( ar_hdr.ar_name[0] != '/' ) {
      char *src = ar_hdr.ar_name;
      const char *e = src + sizeof( ar_hdr.ar_name );
      while( src < e && *src && *src != ' ' && *src != '/' ) {
        *dst++ = *src++;
      }
    } else if( ar_hdr.ar_name[1] == '/' ) {
      string_table = ( char * )malloc( lar_size );
      lseek( fd, offset + SARHDR, 0 );
      if( read( fd, string_table, lar_size ) != lar_size ) {
        printf( "error reading string table\n" );
      }
    } else if( string_table && ar_hdr.ar_name[1] != ' ' ) {
      char *src = string_table + atoi( ar_hdr.ar_name + 1 );
      while( *src != '/' ) {
        *dst++ = *src++;
      }
    }
    *dst = 0;
    if( !strcmp( lar_name, "#1" ) ) {
      int len = atoi( ar_hdr.ar_name + 3 );
      if( read( fd, lar_name, len ) != len ) {
        printf( "error reading archive entry\n" );
      }
      lar_name[len] = 0;
    }
    if( lar_name[0] ) {
      if( DEBUG_BINDSCAN ) {
        printf( "archive name %s found\n", lar_name );
      }
      sprintf( buf, "%s(%s)", archive, lar_name );
      ( *func )( closure, buf, 1, ( time_t )lar_date );
    }
    offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
    lseek( fd, offset, 0 );
  }
  if( string_table ) {
    free( string_table );
  }
  close( fd );
}
